package com.test.iotest.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Iterator;

public class NoBlockServer {
    public static void main(String[] args) throws IOException {
        //获取一个通道
        ServerSocketChannel server = ServerSocketChannel.open();
        //设置非阻塞方式
        server.configureBlocking(false);
        server.bind(new InetSocketAddress(9000));
        //生成一个selector
        Selector selector = Selector.open();
        //将通道注册到该selector，实现多路复用
        server.register(selector, SelectionKey.OP_ACCEPT);
        //阻塞并获取有数据的channel
        while (selector.select() > 0) {
            //获取到本次筛选出来所有需要处理的选择键，可以理解为已就绪的channel
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                //该选择键，也等同于通道表示有新的连接过来
                if (selectionKey.isAcceptable()) {
                    System.out.println("当前线程处于阻塞中，等待客户端连接。。。。。");
                    //获取该连接
                    SocketChannel client = server.accept();
                    //设为非阻塞状态
                    client.configureBlocking(false);
                    //注册到selector上，监听读就绪事件
                    client.register(selector, SelectionKey.OP_READ);
                } else if (selectionKey.isReadable()) {
                    System.out.println("当前线程处于读取数据状态.............");
                    //如果是读就绪事件，则获取就绪的channel
                    SocketChannel client = (SocketChannel) selectionKey.channel();
                    //分配内存
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    //生成一个图片相关的filechannel，保存到指位置。
                    FileChannel fileChannel = FileChannel.open(
                            Paths.get("./test/test.png"),
                            StandardOpenOption.WRITE, StandardOpenOption.CREATE);
                    //将读就绪的channel数据循环写入buffer
                    while (client.read(buffer) > 0) {
                        //将已写入数据的buffer改为读模式
                        buffer.flip();
                        //将buffer中的数据写入到filechannle
                        fileChannel.write(buffer);
                        //重置该buffer
                        buffer.clear();
                    }
                    /**
                     * 当从客户端读取数据完成后，向客户端发送一条信息
                     */
                    ByteBuffer resp = ByteBuffer.allocate(1024);
                    resp.put("I received your picture".getBytes());
                    resp.flip();
                    client.write(resp);
                }
                //该选择键已处理，需删除
                iterator.remove();
            }
        }

    }
}
